package com.handy.easy.admin.config.exception;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.handy.easy.admin.constants.enums.ResultEnum;
import com.handy.easy.admin.vo.ResultVo;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 *
 * @author handy
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 自定义 异常捕获
     *
     * @param exception exception
     * @return ResultVo
     */
    @ExceptionHandler(EasyAdminRuntimeException.class)
    public ResultVo<Void> easyAdminRuntimeException(EasyAdminRuntimeException exception) {
        return exception.getResultEnum() != null ? ResultVo.failure(exception.getResultEnum()) : ResultVo.failure(ResultEnum.FAILURE, exception.getMessage());
    }

    /**
     * 没有权限 异常捕获
     *
     * @param exception exception
     * @return ResultVo
     */
    @ExceptionHandler(NotPermissionException.class)
    public ResultVo<Void> notPermissionException(NotPermissionException exception) {
        return ResultVo.failure(ResultEnum.NOT_PERMISSION);
    }

    /**
     * 没有角色 异常捕获
     *
     * @param exception exception
     * @return ResultVo
     */
    @ExceptionHandler(NotRoleException.class)
    public ResultVo<Void> notRoleException(NotRoleException exception) {
        return ResultVo.failure(ResultEnum.NOT_ROLE);
    }

    /**
     * 参数异常捕获
     *
     * @param exception exception
     * @return ResultVo
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResultVo<Void> httpMessageNotReadableException(HttpMessageNotReadableException exception) {
        exception.printStackTrace();
        return ResultVo.failure(ResultEnum.PARAM_FAILURE);
    }

    /**
     * validation 校验异常
     *
     * @param exception 异常
     * @return Result
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ResultVo<String> bodyValidExceptionHandler(MethodArgumentNotValidException exception) {
        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
        List<String> fields = fieldErrors.stream().map(FieldError::getField).collect(Collectors.toList());
        return ResultVo.failure(ResultEnum.PARAM_FAILURE, fields + " 不能为空");
    }

    /**
     * validation 校验异常
     *
     * @param exception 异常
     * @return Result
     */
    @ExceptionHandler(BindException.class)
    public ResultVo<String> bodyValidExceptionHandler(BindException exception) {
        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
        List<String> fields = fieldErrors.stream().map(FieldError::getField).collect(Collectors.toList());
        return ResultVo.failure(ResultEnum.PARAM_FAILURE, fields + " 不能为空");
    }

    /**
     * NotLoginException 异常捕获
     *
     * @param exception exception
     * @return ResultVo
     */
    @ExceptionHandler(NotLoginException.class)
    public ResultVo<String> handlerNotLoginException(NotLoginException exception) {
        exception.printStackTrace();
        // 判断场景值，定制化异常信息
        String message;
        if (exception.getType().equals(NotLoginException.NOT_TOKEN)) {
            message = "未提供token";
        } else if (exception.getType().equals(NotLoginException.INVALID_TOKEN)) {
            message = "token无效";
        } else if (exception.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
            message = "token已过期";
        } else if (exception.getType().equals(NotLoginException.BE_REPLACED)) {
            message = "token已被顶下线";
        } else if (exception.getType().equals(NotLoginException.KICK_OUT)) {
            message = "token已被踢下线";
        } else {
            message = "当前会话未登录";
        }
        return ResultVo.failure(ResultEnum.TOKEN_FAILURE, message);
    }

}